Shader "MROP/houdini_cloud"
{
    // 此Shader只包含Fragment函数
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Cull Off ZWrite Off ZTest Always // 屏幕后处理标配

        CGINCLUDE
        #pragma target 3.0
        #include "UnityCG.cginc"
        #include "../ShaderLibrary/VertStruct.cginc"   // 输入输出与顶点着色器
        #include "../ShaderLibrary/CloudShape.cginc"   // 云的形状相关
        #include "../ShaderLibrary/CloudColor.cginc"   // 云的颜色相关
        #include "../ShaderLibrary/CloudShadow.cginc"   // 云的颜色相关

        float DownSampleDepth(v2f i) : SV_Target
        {
            const float2 texel_size = 0.5 * _CameraDepthTexture_TexelSize.xy;
            const float2 offsets[4] = {
                // uv再上下左右采样，取最大值
                float2(i.uv + float2(-1, -1) * texel_size),
                float2(i.uv + float2(-1, 1) * texel_size),
                float2(i.uv + float2(1, -1) * texel_size),
                float2(i.uv + float2(1, 1) * texel_size)
            };
            float depth = LinearEyeDepth(tex2D(_CameraDepthTexture, offsets[0]));
            depth = min(depth, LinearEyeDepth(tex2D(_CameraDepthTexture, offsets[1])));
            depth = min(depth, LinearEyeDepth(tex2D(_CameraDepthTexture, offsets[2])));
            depth = min(depth, LinearEyeDepth(tex2D(_CameraDepthTexture, offsets[3])));
            return abs(depth);
        }

        float DownSampleOnce(v2f i): SV_Target
        {
            float3 ray_dir;
            const float3 ray_origin = i.ori;
            const float ray_length = ray_prepare(i.ray.xyz, ray_dir);

            float depth = tex2D(_DownSampleDepth, i.uv).r * ray_length; // 0～1
            depth = abs(depth);

            float2 t_near_far = march_field(ray_origin, ray_dir, 0.0, depth);
            int it_count = 0;
            const float value = ray_marching(ray_origin, ray_dir, i.ray.w, t_near_far, it_count, true);
            // 降低云边界的不透明度，导致交互深度有些问题
            return _debug_iteration && _debug_mode == 1 ? debug_remap(it_count/2) : depth_to_tex(value, t_near_far.y, ray_length);
        }

        float DownSampleTwice(v2f i) : SV_Target
        {
            if (_debug_mode == 1) return 0;
            float3 ray_dir;
            const float3 ray_origin = i.ori;
            const float ray_length = ray_prepare(i.ray.xyz, ray_dir);
            const float down_sample_one = tex2D(_DownSampleOnce, i.uv).r * 15.0 * ray_length;
            const float2 t_near_far = march_field(ray_origin, ray_dir, down_sample_one, 15000.0 * _cloud_scale);
            int it_count = 0;
            const float value = ray_marching(ray_origin, ray_dir, i.ray.w, t_near_far, it_count, false);
            return _debug_iteration && _debug_mode == 2 ? debug_remap(it_count) : depth_to_tex(value, t_near_far.y, ray_length);
        }

        float DownSampleThird(v2f i) : SV_Target
        {
            if (_debug_mode == 1 || _debug_mode == 2) return 0;
            float3 ray_dir;
            const float3 ray_origin = i.ori;
            const float ray_length = ray_prepare(i.ray.xyz, ray_dir);
            const float down_sample_two = tex2D(_DownSampleTwice, i.uv).r * 15.0 * ray_length;
            const float2 t_near_far = march_field(ray_origin, ray_dir, down_sample_two, 15000.0 * _cloud_scale);
            int it_count = 0;
            const float value = ray_marching(ray_origin, ray_dir, i.ray.w, t_near_far, it_count, false);
            return _debug_iteration && _debug_mode == 3 ? debug_remap(it_count) : depth_to_tex(value, t_near_far.y, ray_length);
        }

        float3 DownSampleShadowMap(v2f i) : SV_Target
        {
            if (_debug_mode == 1 || _debug_mode == 2 || _debug_mode == 3) return 0;
            const float3 ray_origin = i.ori;
            float3 ray_dir;
            const float ray_length = ray_prepare(i.ray.xyz, ray_dir);
            float down_sample_three = tex2D(_DownSampleThird, i.uv).r;
            if (down_sample_three>=10000) return float3(0,0,0);
            down_sample_three *= 15.0 * ray_length;

            const float3 light_dir = normalize(-_WorldSpaceLightPos0.xyz);
            const float3 start_pos = ray_origin + ray_dir * down_sample_three;
            const float3 light_pos = get_light_plane_point(-light_dir); // 平面光所过的点，应该是某一个角点
            const float to_light_dist = (dot(light_dir, start_pos - light_pos));
            const float3 shadow_orig = start_pos - light_dir * to_light_dist;
            const float2 shadow_t_near_far = float2(march_field(shadow_orig, light_dir, 0.0, 15000.0 * _cloud_scale).x, to_light_dist);
            const float3 soft_shadow = shadow_march(shadow_orig, light_dir, shadow_t_near_far, to_light_dist, 1000);
            return soft_shadow; // r：阴影遮罩 g：
        }

        fixed4 ColorCloud(v2f i) : SV_Target
        {
            if (_debug_mode == 1 || _debug_mode == 2 || _debug_mode == 3 || _debug_mode == 4) return 0;
            float3 ray_dir;
            const float3 ray_origin = i.ori;
            const float ray_length = ray_prepare(i.ray.xyz, ray_dir);
            const float down_sample_three = tex2D(_DownSampleThird, i.uv).r * 15.0 * ray_length;
            const float2 t_near_far = march_field(ray_origin, ray_dir, down_sample_three, 15000.0 * _cloud_scale);
            // int it_count = 0;
            // const float end_depth = ray_marching(ray_origin, ray_dir, i.ray.w, t_near_far, it_count, false);

            // if (_debug_iteration && _debug_mode == 3) return debug_remap(it_count);
            // float result = depth_to_tex(end_depth, t_near_far.y, ray_length);

            fixed4 output_color = 0;
            if (down_sample_three < t_near_far.y)
            {
                // do shadow
                const float3 light_dir = normalize(-_WorldSpaceLightPos0.xyz);
                const float3 start_pos = ray_origin + ray_dir * down_sample_three;
                const float3 light_pos = get_light_plane_point(-light_dir); // 平面光所过的点，应该是某一个角点
                const float to_light_dist = dot(light_dir, start_pos - light_pos);// 当前渲染位置位置到光平面的距离
                const float3 shadow_orig = start_pos - light_dir * to_light_dist; // 当前位置对应光平面上光线步进发射点
                const float2 shadow_t_near_far = float2(march_field(shadow_orig, light_dir, 0.0, 15000.0 * _cloud_scale).x, to_light_dist);
                const float3 soft_shadow = shadow_march(shadow_orig, light_dir, shadow_t_near_far, to_light_dist, 1000);
                // output_color = float4(soft_shadow.xxx, 1.0);
                output_color = calculate_color(ray_origin, ray_dir, down_sample_three, light_dir, soft_shadow);
                
                // output_color = calculate_color(ray_origin, ray_dir, down_sample_three, light_dir, tex2D(_Shadowmap, i.uv));
            }
            // return float4(depth.xxx/10, 1.0);
            return output_color;
        }

        fixed4 OutputImage(v2f i) : SV_Target
        {
            // TODO: 执行背景颜色和云的混合
            int scale = 10000;
            if (_debug_iteration) scale = 1;
            switch (_debug_mode)
            {
            case 0:
                return tex2D(_DownSampleDepth, i.uv) / scale;
            case 1:
                return tex2D(_DownSampleOnce, i.uv) / scale;
            case 2:
                return tex2D(_DownSampleTwice, i.uv) / scale;
            case 3:
                return tex2D(_DownSampleThird, i.uv) / scale;
            case 4:
                return tex2D(_Shadowmap, i.uv);
            case 5:
                return tex2D(_ColorCloud, i.uv);
            default:
                const float4 col = tex2D(_ColorCloud, i.uv);
                const float3 bg = tex2D(_MainTex, i.uv);
                return half4(lerp(col.xyz, bg, 1.0 - col.w), 1.0);
            }
        }
        ENDCG

        Pass
        {
            Name "DownSampleDepth"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment DownSampleDepth
            ENDCG
        }
        Pass
        {
            Name "DownSampleOnce"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment DownSampleOnce
            ENDCG
        }
        Pass
        {
            Name "DownSampleTwice"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment DownSampleTwice
            ENDCG
        }
        Pass
        {
            Name "DownSampleThird"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment DownSampleThird
            ENDCG
        }
        Pass
        {
            Name "DownSampleShadowMap"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment DownSampleShadowMap
            ENDCG
        }
        Pass
        {
            Name "CloudColor"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment ColorCloud
            ENDCG
        }
        Pass
        {
            Name "OutputImage"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment OutputImage
            ENDCG
        }
    }
}